<html>

<head>
<title>WebGL game lib</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">

<script type="text/javascript" src="sylvester.js"></script>
<script type="text/javascript" src="glUtils.js"></script>
<script type="text/javascript" src="curve.js"></script>
<script type="text/javascript" src="camera.js"></script>
<script type="text/javascript" src="key.js"></script>
<script type="text/javascript" src="matrixstack.js"></script>
<script type="text/javascript" src="shaderManager.js"></script>
<script type="text/javascript" src="actor.js"></script>

<!- 白色で描画するshader ->
<script id="white-fs" type="x-shader/x-fragment">
  #ifdef GL_ES
  precision highp float;
  #endif

  void main(void) {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
  }
</script>

<script id="white-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;

  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;

  void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
  }
</script>

<!- 指定した頂点カラーで描画するshader ->
<script id="vertex-color-fs" type="x-shader/x-fragment">
  #ifdef GL_ES
  precision highp float;
  #endif

  varying vec4 vColor;

  void main(void) {
    gl_FragColor = vColor;
  }
</script>
<script id="vertex-color-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;
  attribute vec4 aVertexColor;

  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;

  varying vec4 vColor;

  void main(void) {
      gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
      vColor = aVertexColor;
  }
</script>

<script type="text/javascript">

    var gl; 
    var keyManager = KeyManager.create();
    var camera = CameraSystem.create();
    var matrixStack = MatrixStack.create();
    var shaderManager;
    var actorManager;
    function initGL(canvas) {
        try {
            // gl contextの初期化
            gl = canvas.getContext("experimental-webgl");
            gl.viewportWidth = canvas.width;
            gl.viewportHeight = canvas.height;

            // MatrixStackの初期化
            matrixStack.init();
            
            // cameraの初期化
            camera.initialize(canvas.width, canvas.height, 45, canvas.width/canvas.height, 0.1, 100);

            // shader managerの初期化
            shaderManager = ShaderManager.create(camera, matrixStack);
            shaderManager.setTable("white", "white-vs", "white-fs", 
                    function(){
                        this.locAttrVertex = gl.getAttribLocation(this, "aVertexPosition");

                        this.locUnifPmatrix = gl.getUniformLocation(this, "uPMatrix");
                        this.locUnifMVmatrix = gl.getUniformLocation(this, "uMVMatrix");
                    },
                    function(mvMatrix, model){
                        //gl.uniformMatrix4fv(this.locUnifPmatrix, false, new Float32Array(pMatrix.flatten()));
                        //gl.uniformMatrix4fv(this.locUnifPmatrix, false, pMatrixFlatten);
                        gl.enableVertexAttribArray(this.locAttrVertex);
                        gl.uniformMatrix4fv(this.locUnifMVmatrix, false, new Float32Array(mvMatrix.flatten()));
                        gl.bindBuffer(gl.ARRAY_BUFFER, model.buffer);
                        gl.vertexAttribPointer(this.locAttrVertex, model.itemSize, gl.FLOAT, false, 0, 0);
                        });
            shaderManager.setTable("vertex-color", "vertex-color-vs", "vertex-color-fs", 
                    function(){
                        this.locAttrVertex = gl.getAttribLocation(this, "aVertexPosition");

                        this.locAttrColor = gl.getAttribLocation(this, "aVertexColor");

                        this.locUnifPmatrix = gl.getUniformLocation(this, "uPMatrix");
                        this.locUnifMVmatrix = gl.getUniformLocation(this, "uMVMatrix");
                    },
                    function(mvMatrix, model){
                        //gl.uniformMatrix4fv(this.locUnifPmatrix, false, new Float32Array(pMatrix.flatten()));
                        gl.uniformMatrix4fv(this.locUnifMVmatrix, false, new Float32Array(mvMatrix.flatten()));
                        gl.bindBuffer(gl.ARRAY_BUFFER, model.vertexBuffer);
                        gl.vertexAttribPointer(this.locAttrVertex, model.vertexItemSize, gl.FLOAT, false, 0, 0);
                        gl.enableVertexAttribArray(this.locAttrVertex);
                        gl.bindBuffer(gl.ARRAY_BUFFER, model.colorBuffer);
                        gl.vertexAttribPointer(this.locAttrColor, model.colorItemSize, gl.FLOAT, false, 0, 0);
                        gl.enableVertexAttribArray(this.locAttrColor);
                        });
            // ActorManagerの初期化
            actorManager = ActorManager.create(matrixStack, shaderManager);
        } catch(e) {
            alert(e);
        }
        if (!gl) {
            alert("Could not initialise WebGL, sorry :-(");
        }
    }

    function initKey()
    {
        keyManager.initialize(document);
        keyManager.setDownCallback(function(c){
                if (String.fromCharCode(c) == "I"){
                    camera.eye_pos.elements[0] = 
                    camera.eye_pos.elements[1] = 
                    camera.eye_pos.elements[2] = 0;
                    camera.eye_rvect.elements[0] = 0;
                    camera.eye_rvect.elements[1] = 0;
                    camera.eye_rvect.elements[2] = 1;
                }
                if (String.fromCharCode(c) == "A"){
                    camera.lookAt(-1.5, 0, -7.0);
                }
                if (String.fromCharCode(c) == "C"){
                    camera.addHermiteAnimation(
                        5000, 
                        null, null,
                        [-10, 0, -6],
                        [-1, 0, 0]
                        //[0, 0, 0],
                        //[0, 0, 1]
                        );
                }
                //alert(c);
                });
        keyManager.setIntervalCallback(function(){
                // 左
                if (keyManager.keyPressed[37]){
                    camera.move(-0.5,0,0);
                }
                // 右
                if (keyManager.keyPressed[39]){
                    camera.move(0.5,0,0);
                }
                // 上 
                if (keyManager.keyPressed[38]){
                    camera.eye_pos.elements[1] += 0.1;
                }
                // 下
                if (keyManager.keyPressed[40]){
                    camera.eye_pos.elements[1] -= 0.1;
                }
                // PageUp
                if (keyManager.keyPressed[33]){
                    camera.move(0,0,-0.5);
                }
                // PageDown
                if (keyManager.keyPressed[34]){
                    camera.move(0,0,0.5);
                }
                // h
                if (keyManager.keyPressed[72]){
                    camera.yaw(0.5*Math.PI/180);
                }
                // l
                if (keyManager.keyPressed[76]){
                    camera.yaw(-0.5*Math.PI/180);
                }
                // j
                if (keyManager.keyPressed[74]){
                    camera.pitch(0.5*Math.PI/180);
                }
                // k
                if (keyManager.keyPressed[75]){
                    camera.pitch(-0.5*Math.PI/180);
                }
                // l
                //if (keyManager.keyPressed[76]){
                //    if (keyManager.keyPressed[88]){
                //        camera.pitch(-0.5*Math.PI/180);
                //    } else if (keyManager.keyPressed[89]){
                //        camera.yaw(-0.5*Math.PI/180);
                //    } else {
                //        var matrix = Matrix.RotationY(-0.5*Math.PI/180);
                //        camera.eye_rvect = matrix.x(camera.eye_rvect);
                //    }
                //}
                //// r
                //if (keyManager.keyPressed[82]){
                //    if (keyManager.keyPressed[88]){
                //        camera.pitch(0.5*Math.PI/180);
                //    } else if (keyManager.keyPressed[89]){
                //        camera.yaw(0.5*Math.PI/180);
                //    } else {
                //        var matrix = Matrix.RotationY(0.5*Math.PI/180);
                //        camera.eye_rvect = matrix.x(camera.eye_rvect);
                //    }
                //}
            }, 15);
    }


  //var triangle = {};
  //var square = {};
  //function initBuffers() {
  //  triangle.shaderId = 0;
  //  triangle.buffer = gl.createBuffer();
  //  gl.bindBuffer(gl.ARRAY_BUFFER, triangle.buffer);
  //  var vertices = [
  //       0.0,  1.0,  0.0,
  //      -1.0, -1.0,  0.0,
  //       1.0, -1.0,  0.0
  //  ];
  //  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  //  triangle.itemSize = 3;
  //  triangle.numItems = 3;
  //  triangle.matrix = Matrix.Translation4x4(-1.5, 0, -7);

  //  square.shaderId = 0;
  //  square.buffer = gl.createBuffer();
  //  gl.bindBuffer(gl.ARRAY_BUFFER, square.buffer);
  //  vertices = [
  //       1.0,  1.0,  0.0,
  //      -1.0,  1.0,  0.0,
  //       1.0, -1.0,  0.0,
  //      -1.0, -1.0,  0.0
  //  ];
  //  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  //  square.itemSize = 3;
  //  square.numItems = 4;
  //  square.matrix = Matrix.Translation4x4(1.5, 0, -7); 
  //}
    function createTriangleModel(scale) {
        var model = {};
        model.shaderId = "white";
        model.buffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, model.buffer);

        var s = scale || 1.0;
        var vertices = [
            0.0,  s,  0.0,
             -s, -s,  0.0,
              s, -s,  0.0
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        model.itemSize = 3;
        model.numItems = 3;
        return model;
    }

    function createSquareModel(scale) {
        var model = {};
        model.shaderId = "white";
        model.buffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, model.buffer);

        var s = scale || 1.0;
        var vertices = [
             s,  s,  0.0,
            -s,  s,  0.0,
             s, -s,  0.0,
            -s, -s,  0.0
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        model.itemSize = 3;
        model.numItems = 4;
        return model;
    }

    function createAxisModel(scale) {
        var model = {};
        model.shaderId = "vertex-color";
        var s = scale || 1.0;
        var min = 0.2;
        var vertices = [
            -min*s, 0, 0,
            s, 0, 0,
            0, -min*s, 0,
            0, s, 0,
            0, 0, -min*s,
            0, 0, s
        ];
        model.vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, model.vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        model.vertexItemSize = 3;
        model.numItems = 6;

        var colors = [
            1, 0, 0, 1,
            1, 0, 0, 1,
            0, 1, 0, 1,
            0, 1, 0, 1,
            0.1, 0.1, 1, 1,
            0.1, 0.1, 1, 1,
        ];
        model.colorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, model.colorBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
        model.colorItemSize = 4;
        return model;
    }

    function initActors(){
        var triangleModel = createTriangleModel(1);
        var triangleDraw = function(model){
                        gl.drawArrays(gl.TRIANGLES, 0, model.numItems);
        };
        triangleModel.drawFunc = triangleDraw;
        var actorTriangle = Actor.create(
                Matrix.Translation4x4(-1.5, 0, -7),
                triangleModel);
        actorTriangle.exec = function(){
            this.matrix = this.matrix.x(Matrix.RotationZ(0.5*Math.PI/180).ensure4x4());
        };
        actorManager.addActor(actorTriangle);

        //var actorTriangle2 = Actor.create(
        //        Matrix.Translation4x4(-1.5, 2.0, -8),
        //        triangleModel);
        //actorManager.addActor(actorTriangle2);

        var squareModel = createSquareModel();
        squareModel.drawFunc = function(model){
                        gl.drawArrays(gl.TRIANGLE_STRIP, 0, model.numItems);
                    };
        var actorSquare = Actor.create(
                Matrix.Translation4x4(1.5, 0, -7),
                squareModel);
        actorSquare.exec = function(){
            this.matrix = this.matrix.x(Matrix.RotationY(0.5*Math.PI/180).ensure4x4());
        };
        actorManager.addActor(actorSquare);

        var axisModel = createAxisModel(1);
        axisModel.drawFunc = function(model){
            //gl.lineWidth(3);
            gl.drawArrays(gl.LINES, 0, model.numItems);
        };
        var actorAxis = Actor.create(
                Matrix.Translation4x4(0, 0, 0),
                axisModel);
        actorManager.addActor(actorAxis);
        actorManager.setAxisModel(actorAxis.model);
    }

  function drawScene() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var d0 = document.getElementById("d0");
    d0.innerHTML = camera.getMatrixString();
    var d1 = document.getElementById("d1");
    d1.innerHTML = camera.getCameraString();

    var cameraMatrix = camera.exec();
    actorManager.execAllActor();
    matrixStack.push(cameraMatrix);
    {
        actorManager.drawAllActor();
        actorManager.drawAllActorAxis();
    }
    matrixStack.pop();
  }

  function webGLStart() {
    var canvas = document.getElementById("test-canvas");
    initGL(canvas);
    initKey();
    //initBuffers();
    initActors();

    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    gl.clearDepth(1.0);

    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);

    setInterval(drawScene, 15);
  }
    var startCamera = {};
    function button1(){
        startCamera.pos = camera.eye_pos.dup();
        startCamera.rvect = camera.eye_rvect.dup();
        var d2 = document.getElementById("d2");
        d2.innerHTML = "start:<BR>" + camera.getCameraString();
    }

    var endCamera = {};
    function button2(){
        endCamera.pos = camera.eye_pos.dup();
        endCamera.rvect = camera.eye_rvect.dup();
        var d3 = document.getElementById("d3");
        d3.innerHTML = "end:<BR>" + camera.getCameraString();
    }

    function button3(){
        var time = document.getElementById("time").value;
        
        camera.addHermiteAnimation(
            parseFloat(time) || 5000, 
            startCamera.pos.elements,
            startCamera.rvect.elements,
            endCamera.pos.elements,
            endCamera.rvect.elements);

    }
</script>
</head>
<body onload="webGLStart();">
    <table>
        <tr>
            <td>
                <canvas id="test-canvas" style="border: none;" width="500" height="500"></canvas>
            </td>
            <td>
                <table>
                    <tr>
                        <h4>操作方法</h4>
                        カメラをキーボードから動かせます<br>
                        <ul>
                            <li>カーソルキー：前後左右の移動</li>
                            <li>PageUp：カメラの前進</li>
                            <li>PageDown：カメラの後退</li>
                            <li>h/l：カメラの向きを左右に変える</li>
                            <li>j/k：カメラの向きを上下に変える</li>
                            <li>i：カメラを初期位置へ戻す</li>
                            <li>a：三角形の方を向きます</li>
                        </ul>
                        <p>
                        下のボタンから現在のカメラを、カメラアニメーションの開始と終了として登録できます。<br>
                        カメラの移動完了までに掛かる時間も変更できます。<br>
                        (大きい数字ほどゆっくりと動きます)<br>
                        移動開始ボタンを押すとカメラの移動が始まります。<br>
                    </tr>
                    <tr><h5>カメラ情報</h5></tr>
                    <tr><div id="d0"></div></tr>
                    <tr><div id="d1"></div></tr>
                </table>
            </td>
        </tr>
    </table>
  <p>
  <input type="button" id="button1" value="開始カメラ保存" onclick="button1()"> 
  <input type="button" id="button2" value="終了カメラ保存" onclick="button2()">
  移動時間<input type="text" id="time" value="5000">
  <input type="button" id="button3" value="カメラ移動開始" onclick="button3()">
  <p>
  <div id="d2"></div>
  <div id="d3"></div>
</body>
</html>

